package wiki.xsx.core.handler;

import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import wiki.xsx.core.config.redisson.RedissonClientHelper;
import wiki.xsx.core.config.redisson.RedissonConnectionFactory;
import wiki.xsx.core.util.ApplicationContextUtil;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 助手管理
 * @author xsx
 * @date 2019/5/23
 * @since 1.8
 */
class HandlerManager {
    /**
     * redis模板(用于对象)
     */
    private static final RedisTemplate<String, Object> REDIS_TEMPLATE = ApplicationContextUtil.getContext().getBean("redisTemplate", RedisTemplate.class);
    /**
     * redis模板(用于字符串)
     */
    private static final StringRedisTemplate STRING_REDIS_TEMPLATE = ApplicationContextUtil.getContext().getBean("stringRedisTemplate", StringRedisTemplate.class);
    /**
     * 助手管理实例
     */
    private static final HandlerManager INSTANCE = new HandlerManager();
    /**
     * 默认KEY
     */
    private static final String DEFAULT_KEY = "default";

    /**
     * 数据库助手字典
     */
    private final ConcurrentMap<String, DBHandler> dbMap= new ConcurrentHashMap<>(256);
    /**
     * 键助手字典
     */
    private final ConcurrentMap<String, KeyHandler> keyMap= new ConcurrentHashMap<>(256);
    /**
     * 数字助手字典
     */
    private final ConcurrentMap<String, NumberHandler> numberMap= new ConcurrentHashMap<>(256);
    /**
     * 字符串助手字典
     */
    private final ConcurrentMap<String, StringHandler> stringMap = new ConcurrentHashMap<>(256);
    /**
     * 列表助手字典
     */
    private final ConcurrentMap<String, ListHandler> listMap = new ConcurrentHashMap<>(256);
    /**
     * 哈希助手字典
     */
    private final ConcurrentMap<String, HashHandler> hashMap = new ConcurrentHashMap<>(256);
    /**
     * 无序集合助手字典
     */
    private final ConcurrentMap<String, SetHandler> setMap = new ConcurrentHashMap<>(256);
    /**
     * 有序集合助手字典
     */
    private final ConcurrentMap<String, ZsetHandler> zsetMap = new ConcurrentHashMap<>(256);
    /**
     * 位图助手字典
     */
    private final ConcurrentMap<String, BitmapHandler> bitmapMap = new ConcurrentHashMap<>(256);
    /**
     * 地理位置助手字典
     */
    private final ConcurrentMap<String, GeoHandler> geoMap = new ConcurrentHashMap<>(256);
    /**
     * 基数助手字典
     */
    private final ConcurrentMap<String, HyperLogLogHandler> hyperLogLogMap = new ConcurrentHashMap<>(256);
    /**
     * lua脚本助手字典
     */
    private final ConcurrentMap<String, ScriptHandler> scriptMap= new ConcurrentHashMap<>(256);
    /**
     * 发布订阅助手字典
     */
    private final ConcurrentMap<String, PubSubHandler> pubSubMap= new ConcurrentHashMap<>(256);
    /**
     * 分布式锁助手字典
     */
    private final ConcurrentMap<String, RedisLockHandler> lockMap= new ConcurrentHashMap<>(256);
    /**
     * 哨兵助手字典
     */
    private final ConcurrentMap<String, SentinelHandler> sentinelMap= new ConcurrentHashMap<>(256);
    /**
     * 集群助手实例
     */
    private final ClusterHandler clusterHandler = ClusterHandler.getInstance(REDIS_TEMPLATE);
    /**
     * 助手管理构造
     */
    private HandlerManager(){}

    /**
     * 获取助手管理
     * @return 返回助手管理实例
     */
    static HandlerManager getManager() {
        return INSTANCE;
    }

    /**
     * 获取默认KEY
     * @return 返回默认KEY
     */
    String getDefaultKey() {
        return DEFAULT_KEY;
    }

    /**
     * 获取数据库助手字典
     * @return 返回数据库助手字典
     */
    ConcurrentMap<String, DBHandler> getDbMap() {
        return this.dbMap;
    }

    /**
     * 获取键助手字典
     * @return 返回键助手字典
     */
    ConcurrentMap<String, KeyHandler> getKeyMap() {
        return this.keyMap;
    }

    /**
     * 获取数字助手字典
     * @return 返回数字助手字典
     */
    ConcurrentMap<String, NumberHandler> getNumberMap() {
        return this.numberMap;
    }

    /**
     * 获取字符串助手字典
     * @return 返回字符串类型助手字典
     */
    ConcurrentMap<String, StringHandler> getStringMap() {
        return this.stringMap;
    }

    /**
     * 获取列表助手字典
     * @return 返回列表助手字典
     */
    ConcurrentMap<String, ListHandler> getListMap() {
        return this.listMap;
    }

    /**
     * 获取哈希助手字典
     * @return 返回哈希助手字典
     */
    ConcurrentMap<String, HashHandler> getHashMap() {
        return this.hashMap;
    }

    /**
     * 获取无序集合助手字典
     * @return 返回无序集合助手字典
     */
    ConcurrentMap<String, SetHandler> getSetMap() {
        return this.setMap;
    }

    /**
     * 获取有序集合助手字典
     * @return 返回有序集合助手字典
     */
    ConcurrentMap<String, ZsetHandler> getZsetMap() {
        return this.zsetMap;
    }

    /**
     * 获取位图助手字典
     * @return 返回位图助手字典
     */
    ConcurrentMap<String, BitmapHandler> getBitmapMap() {
        return this.bitmapMap;
    }

    /**
     * 获取地理位置助手字典
     * @return 返回地理位置助手字典
     */
    ConcurrentMap<String, GeoHandler> getGeoMap() {
        return this.geoMap;
    }

    /**
     * 获取基数助手字典
     * @return 返回基数助手字典
     */
    ConcurrentMap<String, HyperLogLogHandler> getHyperLogLogMap() {
        return this.hyperLogLogMap;
    }

    /**
     * 获取lua脚本助手字典
     * @return 返回lua脚本助手字典
     */
    ConcurrentMap<String, ScriptHandler> getScriptMap() {
        return this.scriptMap;
    }

    /**
     * 获取发布订阅助手字典
     * @return 返回发布订阅助手字典
     */
    ConcurrentMap<String, PubSubHandler> getPubSubMap() {
        return this.pubSubMap;
    }

    /**
     * 获取分布式锁助手字典
     * @return 返回分布式锁助手字典
     */
    ConcurrentMap<String, RedisLockHandler> getLockMap() {
        return this.lockMap;
    }

    /**
     * 获取哨兵助手字典
     * @return 返回哨兵助手字典
     */
    ConcurrentMap<String, SentinelHandler> getSentinelMap() {
        return this.sentinelMap;
    }

    /**
     * 获取集群助手实例
     * @return 返回集群助手实例
     */
    ClusterHandler getClusterHandler() {
        return this.clusterHandler;
    }

    /**
     * 获取连接工厂
     * @param dbIndex 数据库索引
     * @return 返回连接工厂
     */
    static RedisConnectionFactory getConnectionFactory(int dbIndex) {
        RedisConnectionFactory redisConnectionFactory = ApplicationContextUtil.getContext().getBean("redisConnectionFactory", RedisConnectionFactory.class);
        if (redisConnectionFactory instanceof LettuceConnectionFactory) {
            ((LettuceConnectionFactory)redisConnectionFactory).setDatabase(dbIndex);
        }else if (redisConnectionFactory instanceof JedisConnectionFactory) {
            JedisConnectionFactory factory = (JedisConnectionFactory) redisConnectionFactory;
            if (factory.isRedisSentinelAware()) {
                RedisSentinelConfiguration sentinelConfiguration = factory.getSentinelConfiguration();
                if (sentinelConfiguration != null) {
                    sentinelConfiguration.setDatabase(dbIndex);
                }
            }else{
                RedisStandaloneConfiguration standaloneConfiguration = factory.getStandaloneConfiguration();
                if (standaloneConfiguration!=null) {
                    standaloneConfiguration.setDatabase(dbIndex);
                }
            }
        }else if (redisConnectionFactory instanceof RedissonConnectionFactory) {
            redisConnectionFactory = new RedissonConnectionFactory(
                    RedissonClientHelper.createClient(dbIndex)
            );
        }else {
            throw new RuntimeException("no support connection factory");
        }
        return redisConnectionFactory;
    }

    /**
     * 创建对象模板
     * @param dbIndex 数据库索引
     * @return 返回对象模板
     */
    static RedisTemplate<String, Object> createRedisTemplate(int dbIndex) {
        return createTemplate(dbIndex, false);
    }

    /**
     * 创建字符串模板
     * @param dbIndex 数据库索引
     * @return 返回字符串模板
     */
    static StringRedisTemplate createStringRedisTemplate(int dbIndex) {
        return (StringRedisTemplate) createTemplate(dbIndex, true);
    }

    /**
     * 创建模板
     * @param dbIndex 数据库索引
     * @param isString 是否为字符串模板
     * @return 返回模板
     */
    static RedisTemplate createTemplate(int dbIndex, boolean isString) {
        return initRedisTemplate(getConnectionFactory(dbIndex), isString);
    }

    /**
     * 创建模板
     * @param dbIndex 数据库索引
     * @return 返回模板
     */
    static List<RedisTemplate> createTemplate(int dbIndex) {
        RedisConnectionFactory connectionFactory = getConnectionFactory(dbIndex);
        return Arrays.asList(
                initRedisTemplate(connectionFactory, false),
                initRedisTemplate(connectionFactory, true)
        );
    }

    /**
     * 初始化模板
     * @param factory 连接工厂
     * @param isString 是否为字符串模板
     * @return 返回模板
     */
    static RedisTemplate initRedisTemplate(RedisConnectionFactory factory, boolean isString) {
        RedisTemplate redisTemplate;
        if (isString) {
            redisTemplate = new StringRedisTemplate(factory);
        }else{
            redisTemplate = new RedisTemplate<String, Object>();
            redisTemplate.setKeySerializer(REDIS_TEMPLATE.getKeySerializer());
            redisTemplate.setValueSerializer(REDIS_TEMPLATE.getValueSerializer());
            redisTemplate.setHashKeySerializer(REDIS_TEMPLATE.getHashKeySerializer());
            redisTemplate.setHashValueSerializer(REDIS_TEMPLATE.getHashValueSerializer());
            redisTemplate.setConnectionFactory(factory);
            redisTemplate.afterPropertiesSet();
        }
        return redisTemplate;
    }

    /**
     * 获取默认的对象模板
     * @return 返回默认的对象模板
     */
    static RedisTemplate<String, Object> getDefaultRedisTemplate() {
        return REDIS_TEMPLATE;
    }

    /**
     * 获取默认的字符串模板
     * @return 返回默认的字符串模板
     */
    static StringRedisTemplate getDefaultStringRedisTemplate() {
        return STRING_REDIS_TEMPLATE;
    }
}
